package member

import (
    "fmt"
	"time"
	"strings"
	"wxsdk/oauth"
	"encoding/json"
	"dhfshop/controllers/base"
	"dhfshop/models/isv"
	"dhfshop/models/member"
	"dhfshop/models/consts"
	"dhfshop/models/org"
	//"dhfshop/service/wechat"
	"dhfshop/service/redisgo"
    "github.com/pkg/errors"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/validation"
	jwt "github.com/dgrijalva/jwt-go"
)

// 会员管理
type MemberController struct {
	base.BaseController
}

func (this *MemberController) Login() {
	this.ServeOk("this login type is not support now")
	return
}

//公众号登陆,直接调用微信本地API获取code
func (this *MemberController) WeChatLogin() {
	this.ServeOk("this login type is not support now")
	return

}

// 小程序登陆,直接调用微信本地API获取code,encrytedData,iv
func (this *MemberController) AppletWeChatLogin() {
	this.ServeOk("this login type is not support now")
	return
}

// 小程序登陆升级接口
func (this *MemberController) NewAppletWeChatLogin() {
	var (
	    members *member.MemberValue = new(member.MemberValue)
	)
	v := struct {
		PartnerId     int64    `form:"-"`
		AppId         string `form:"app_id" valid:"Required"`
		Code          string `form:"code" valid:"Required"`
		InviterId     int64  `form:"inviter_id"`
	}{}
	this.ParseForm(&v)
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key + " " + valid.Errors[0].Message)
		return
	}
	isvAppID := beego.AppConfig.String("IsvAppID")
	authorize, err := isv.GetAuthorizeByAppId(isvAppID)
	if err != nil {
	    err = errors.Wrap(err, "GetAuthorizeByAppId: ")
		this.ServeError(err.Error())
		return
	}
	basicUser := new(oauth.SessionInfo)
	basicUser, err = oauth.JsCode2Session(v.AppId, isvAppID, authorize.AccessToken, v.Code)
	if err != nil {
	    beego.Debug(err.Error())
		this.ServeError(err.Error())
		return
	}
	if len(basicUser.UnionId) > 3 {
	    if members, err = member.GetMemberIdByUnionid(v.AppId, basicUser.UnionId); err != nil {  //注册用户
		    if members, err = member.GetMemberByOpenId(basicUser.OpenId); err != nil {  //兼容以前存在的openid
			    if members.MemberId, err = member.CreateBasicWeChatMember(v.AppId, basicUser.UnionId, basicUser, v.InviterId); err != nil {
					this.ServeError(err.Error())
					return
				}
			}else{
			   members.OpenID = basicUser.OpenId
			   members.Unionid = basicUser.UnionId
			   members.SessionKey = basicUser.SessionKey
		       member.UpdateMemberByOpenId(members, "unionid", "session_key")
			}
		}else{
		    members.SessionKey = basicUser.SessionKey
		    member.UpdateMemberByUnionId(members, "session_key")
		}
	}else{
	    if members, err = member.GetMemberByOpenId(basicUser.OpenId); err != nil { //注册用户
			if members.MemberId, err = member.CreateBasicWeChatMember(v.AppId, basicUser.OpenId, basicUser, v.InviterId); err != nil {
				this.ServeError(err.Error())
				return
			}
		}else{
		    members.SessionKey = basicUser.SessionKey
		    member.UpdateMemberByOpenId(members, "session_key")
		}
	}
	if members.State == 9 {
	    beego.Debug("member state:", members.State)
	    this.ServeError("会员被锁定")
		return
	}
	token := jwt.New(jwt.GetSigningMethod("HS256"))
	claims := token.Claims.(jwt.MapClaims)
	//
	custAccount, err := isv.GetCustAccountByAppId(v.AppId)
	if err != nil {
		beego.Debug("GetCustAccountByAppId:", err.Error())
	    this.ServeError(err.Error())
		return
	}
	v.PartnerId = custAccount.PartnerId
	//
	claims["CurrentUser"] = struct {
		Id        int
		CompanyId int
		Role      int
		AppId     string
	}{Id:int(members.MemberId), CompanyId:int(v.PartnerId), Role:1, AppId:v.AppId}
	claims["exp"] = time.Now().UTC().Add(time.Hour * 24 * 1).Unix()
	tokenSecret := beego.AppConfig.String("AuthTokenSecret")
	tokenString, err := token.SignedString([]byte(tokenSecret))
	if err != nil {
		this.ServeError("登录失败，请稍后再试")
		return
	}
	var authUser *org.AuthenticatedUser // null
	memberIdStr := fmt.Sprintf("%d", members.MemberId)
	loginStoreIdStr := fmt.Sprintf("%d", members.LoginStoreId)
	redisconn := redisgo.GetInstance()
	if ok, _:= redisconn.Exists(memberIdStr); ok {
		redisconn.Del(memberIdStr)  //删除老的已存在key
	}
	if authUserJSON, err := json.Marshal(authUser); err == nil {
		if _, err = redisconn.Set(memberIdStr, string(authUserJSON), 24*3600); err != nil {
			beego.Debug("SETEX", err.Error())
		}
	}
	this.Data["json"] = map[string]string{
		"member_id": memberIdStr,
		"token":     tokenString,
		"login_store_id": loginStoreIdStr,
	}
	this.ServeJSON()
}

func (this *MemberController) Logout() {
	v := member.MemberValue{}
	this.ParseForm(&v)
	//curUserId := this.Ctx.Input.GetData("curUserId").(int)
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key + " " + valid.Errors[0].Message)
		return
	}
	this.ServeOk("登出成功")
}

func (this *MemberController) Create() {
	v := member.MemberValue{}
	this.ParseForm(&v)
	valid := validation.Validation{}
	//valid.Required(v.PartnerId, "partner_id")
	valid.Required(v.MemberName, "user_name")
	valid.Required(v.Password, "password")
	valid.Required(v.PasswordConfirm, "password_confirm")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key + " " + valid.Errors[0].Message)
		return
	}
	if v.Password != v.PasswordConfirm {
		this.ServeError("password and password_confirm are not equal")
		return
	}
	memberId, err := member.CreateMember(0, v.MemberName, v.Password)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	rsp := struct {
		MemberId  int64     `json:"member_id"`
		Created time.Time `json:"created"`
	}{MemberId: memberId, Created: time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *MemberController) GetCurrentUser() {
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	member, err := member.GetMemberById(int64(curUserId))
	if err != nil {
		this.ServeError("用户信息不存在")
		return
	}
	this.Data["json"] = member
	this.ServeJSON()
}

func (this *MemberController) GetMemberBasicInfo() {
	//curUserId := this.Ctx.Input.GetData("curUserId").(int)
	openId := this.GetString("open_id")
	memberIdStr := this.GetString("member_id")
	if openId == "" && memberIdStr == "" {
	    this.ServeError("open_id or member_id is null")
	    return
	}
	member, err := member.GetMemberByIdOrOpenId(memberIdStr, openId)
	if err != nil {
		this.ServeError("用户信息不存在")
		return
	}
	rsp := struct {
	    OpenId    string   `json:"open_id"`
		NickName  string   `json:"nick_name"`
		AvatarURL string   `json:"avatar_url"`
	}{OpenId:member.OpenID,NickName:member.Name,AvatarURL:member.Avatar}
	this.Data["json"] = rsp
	this.ServeJSON()
}

type WxMember struct {
	MemberId   int64   `json:"member_id"`
	OpenId     string  `json:"open_id"`
	NickName   string  `json:"nick_name"`     
	AvatarURL  string  `json:"avatar_url"`
	Province   string  `json:"province"`
	City       string  `json:"city"`          
	Country    string  `json:"country"`  
	Unionid    string  `json:"unionid"`
	Phone      string  `json:"phone"`
	Level      int     `json:"level"`
	Remark     string  `json:"remark"`
}
	
func (this *MemberController) List() {
	query,_,fields,order_by,offset,limit,err := this.GetQueryPara()
	if err != nil {
	   this.ServeError(err.Error())
	   return
	}
	appIds := []string{}
	partnerId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
	if accounts, err := isv.QueryCustAccountsByPartnerId(partnerId, 0, 100); err != nil {
	   this.ServeError(err.Error())
	   return
	} else {
	    for _, account := range accounts {
		    appIds = append(appIds, account.AppId)
		}
	}
	//beego.Debug("partnerId:", partnerId)
	//beego.Debug("appIds:", strings.Join(appIds, ","))
	list, cnt, err := member.GetAllMembers(appIds,query,fields,order_by,offset,limit)
	if err != nil {
	    this.ServeError(err.Error())
		return
	}
	wxMembers := []WxMember{}
	for _, value := range list {
	    wxMember := WxMember{MemberId:value.MemberId,OpenId:value.OpenID,NickName:value.Name,AvatarURL:value.Avatar,
		                    Province:value.Province,City:value.City,Country:value.Country,
							Unionid:value.Unionid,Phone:value.Phone,Level:value.Level,Remark:value.Remark}
	    wxMembers = append(wxMembers, wxMember)
	}
	rsp := struct {
	    TotalCount  int64      `json:"total_count"`
	    WxMember    []WxMember `json:"wx_members"`
	}{TotalCount: cnt, WxMember: wxMembers}
	this.Data["json"] = rsp
	this.ServeJSON()
}


func (this *MemberController) Put() {
	var v member.MemberValue
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Required(v.MemberId, "member_id")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return 
	}
	excludeArr := []string{""}
	updateFields, err := this.GetUpdateFields(v, "", "form", excludeArr)
	if err != nil {
	   this.ServeError(err.Error())
		return
	}
	if len(v.BirthDayStr) > 0 {
	    v.BirthDay, _ = time.Parse(consts.DATETIME_FORMAT,v.BirthDayStr)
	}
	if len(updateFields) > 0 {
		if err = member.UpdateMemberById(&v, updateFields...); err != nil{
		    this.ServeError(err.Error())
		    return
	    }	
	}
	rsp := struct {
		    MemberId  int64       `json:"member_id"`
	        Modified  time.Time   `json:"modified"`
	    }{MemberId:v.MemberId, Modified:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *MemberController) MemberLock() {
	 v := struct {
	    MemberId int64  `form:"member_id"`
		Mode     int    `form:"mode"`
	}{}
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Required(v.MemberId, "member_id")
	valid.Range(v.Mode,1,2,"mode")
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return 
	}
	state := 0
	if v.Mode == 1 {
	   state = 9
	}
	if err := member.UpdateMemberStateById(v.MemberId, state); err != nil{
		this.ServeError(err.Error())
		return
	}
	rsp := struct {
		    MemberId  int64       `json:"member_id"`
	        Modified  time.Time   `json:"modified"`
	    }{MemberId:v.MemberId, Modified:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}

func (this *MemberController) WechatBasicPut() {
	v := struct {
		AppId          string `form:"app_id" valid:"Required"`
		NickName       string `form:"nick_name"`
		AvatarUrl      string `form:"avatar_url"`
		EncryptedData  string `form:"encryptedData"`
		Iv             string `form:"iv"`
	}{}
	this.ParseForm(&v)
	valid := validation.Validation{}
	passed, _ := valid.Valid(&v)
	if !passed {
		this.ServeError(valid.Errors[0].Key+" "+valid.Errors[0].Message)
		return 
	}
	curSysRoleId := this.Ctx.Input.GetData("curRoleId").(int) 
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	encrypted_data := strings.Replace(v.EncryptedData, " ", "", -1)
	iv := strings.Replace(v.Iv, " ", "", -1)
	if len(encrypted_data) > 10 && len(iv) > 2 {
		//beego.Debug("member_id:",curUserId,encrypted_data,iv)
		sessionKey := ""
		if curSysRoleId == 1 {
	        if member, err := member.GetMemberById(curUserId); err == nil {
				sessionKey = member.SessionKey
			}
		} else if curSysRoleId == 2 {
		    if user, err := org.GetUserByUserId(curUserId); err == nil {
				sessionKey = user.SessionKey
			}
		} else {
		   beego.Debug("cur sys role is invalid")
		}
		if len(sessionKey) < 5 {
			beego.Debug("member_id:", curUserId, "session key is invalid")
			this.ServeError(fmt.Sprintf("session key is invalid, user_id:", curUserId))
			return
		}
		//beego.Debug("member_id:", curUserId, "sessionKey:", sessionKey)
		userInfo, err := oauth.DecryptedAppUserInfo(sessionKey, encrypted_data, iv)
		if err != nil {
			beego.Debug("member_id:", curUserId, "err:", err.Error())
			this.ServeError(err.Error())
			return
		}
		if curSysRoleId == 1 {
	        members := &member.MemberValue{MemberId:curUserId,Name:userInfo.NickName,Avatar:userInfo.AvatarURL,Sex:userInfo.Gender,
			                Country:userInfo.Country,Province:userInfo.Province,City:userInfo.City,Unionid:userInfo.UnionId}
			if err := member.UpdateMemberById(members,"name","avatar","sex","country","province","city","unionid"); err != nil {
				this.ServeError(err.Error())
				return
			}
		} else if curSysRoleId == 2 {
		    users := &org.User{UserId:curUserId,NickName:userInfo.NickName,Avatar:userInfo.AvatarURL,Country:userInfo.Country,
			                   Province:userInfo.Province,City:userInfo.City,Unionid:userInfo.UnionId}
			if err := org.UpdateUsersById(users,"nick_name","avatar","country","province","city","unionid"); err != nil {
				this.ServeError(err.Error())
				return
			}
		} else {
		   beego.Debug("cur sys role is invalid")
		}
	}else{
	    if curSysRoleId == 1 {
	        members := &member.MemberValue{MemberId:curUserId,Name:v.NickName,Avatar:v.AvatarUrl}
			if err := member.UpdateMemberById(members, "name", "avatar"); err != nil {
				this.ServeError(err.Error())
				return
			}
		} else if curSysRoleId == 2 {
		    users := &org.User{UserId:curUserId,NickName:v.NickName,Avatar:v.AvatarUrl}
			if err := org.UpdateUsersById(users, "nick_name", "avatar"); err != nil {
				this.ServeError(err.Error())
				return
			}
		} else {
		   beego.Debug("cur sys role is invalid")
		}
	}
	rsp := struct {
		UserId    int64       `json:"user_id"`
		OpenId    string      `json:"open_id"`
	    Modified  time.Time   `json:"modified"`
	}{UserId:curUserId,OpenId:"",Modified:time.Now().UTC()}
	this.Data["json"] = rsp
	this.ServeJSON()
}
